#pragma once

#include <iostream>
#include <string>
#include <vector>
#include "InetAddr.hpp"
#include "ThreadPool.hpp"
#include "Thread.hpp"

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

using task_t = std::function<void()>;

class MessageRoute
{
    private:
    bool isExist(const InetAddr& addr)
    {
        for(auto& e: _online_user)
        {
           
            if(e == addr)
                return true;
        }
        return false;
    }

    public:
    MessageRoute()
    {
        pthread_mutex_init(&_mutex,nullptr);
    }
    void Adduser(const InetAddr& addr)
    {
        LockGuard lock(_mutex);
        if(isExist(addr)) return;
        _online_user.push_back(addr);
    }
    void Deluser(const InetAddr& addr)
    {
        LockGuard lock(_mutex);
        if(!isExist(addr)) return;
        for(auto iter = _online_user.begin();iter!=_online_user.end();++iter)
        {
            if(*iter == addr)
                _online_user.erase(iter);
            break;    
        }
        
    }
    void RouteHelper(int sockfd,std::string message,InetAddr who)
    {
        LockGuard lock(_mutex);
        //每一个线程要执行的方法
        //这里auto不能是引用是因为临时变量不能取地址
        for(auto& e:_online_user){
            struct sockaddr_in  temp = e.Addr();
            std::string content = "[" + e.Ip() + ":" + std::to_string(e.Port())+"]"+message+"\n";
            ::sendto(sockfd,content.c_str(),content.size(),0,(struct sockaddr*)&temp,sizeof(temp));
        }
    }
    void Route(int sockfd,std::string message,InetAddr who)
    {
        //转发前，判断能否插入
        Adduser(who);

        //如果客户端要退出，则将退出消息同样转发
        if(message=="Q" || message=="q" || message=="quit")
        Deluser(who);
        
        //让转发功能由线程池来做

        task_t task =  std::bind(&MessageRoute::RouteHelper,this,sockfd,message,who);
        ThreadPool<task_t>::GetInstance()->Enqueue(task); 

    }
    ~MessageRoute()
    {
        pthread_mutex_destroy(&_mutex);
    }
    private:
    std::vector<InetAddr> _online_user;


    pthread_mutex_t _mutex;
};